<template>
  <div class="editPage__video">
    <div class="img__con">
      <template v-if="uploadVideo.url">
        <el-button
          style="width: 60px"
          type="danger"
          size="mini"
          icon="el-icon-close"
          @click="handleDelete"
        />
      </template>
      <el-upload
        class="avatar-uploader"
        :action="`/api/not404`"
        :http-request="uploadHttp"
        :show-file-list="false"
        :multiple="true"
        :before-upload="handleBeforeUpload"
        :headers="headers"
      >
        <template v-if="uploadVideo.url">
          <video :key="menuKey" width="200" height="200" controls="controls">
            <source :src="uploadVideo.url" type="video/mp4">
          </video>
        </template>
        <template v-else>
          <el-button>上传<i class="el-icon-upload el-icon--right" /></el-button>
        </template>
      </el-upload>
      <p class="font-12 font-color-2">说明: 视频格式为mp4格式，视频大小不超过2000MB</p>
      <p class="font-12 font-color-2">剧集名称命名必须为数字，例如1.mp4</p>
      <template v-if="aliError">
        <p class="font-12" style="color: red">请求阿里云接口错误，程序异常已中断，请刷新当前页重新，上传剩余剧集</p>
      </template>
    </div>

    <template v-if="filePlanList.length > 0">
      <div class="plan-nav">
        <div v-for="item in filePlanList" :key="item.fileName" class="plan-item">
          <p class="font-color font-14">{{ item.fileName }}</p>
          <p class="ml-10 mr-10">/</p>
          <p class="font-color font-14 mr-50">{{ item.fileSize }}MB</p>
          <template v-if="item.progress">
            <el-progress :percentage="item.progress" />
          </template>
          <template v-else>
            <i class="el-icon-loading" />
          </template>
        </div>
      </div>
    </template>

  </div>
</template>

<script>
import { queryGetStsToken } from '@/api/oss/oss'
import OSS from 'ali-oss'
import { getToken } from '@/utils/auth'
import { addBatchEpisode } from '@/api/video/library'
import { isRelogin } from '@/utils/request'

export default {
  props: {
    library_id: {
      type: String,
      default: ''
    },
    video_folder: {
      type: String,
      default: ''
    }
  },
  data() {
    return {
      uploadVideo: {},
      menuKey: 1, // 用来强制刷新
      headers: {
        Authorization: 'Bearer ' + getToken()
      },
      fileList: [],
      filePlanList: [], // 上传状态，仅展示
      client: {},
      timer: null,
      aliError: false // 阿里云oss直传异常
    }
  },
  watch: {
    videoSrc: {
      handler(val) {
        this.menuKey++
        this.uploadVideo.url = val
      },
      immediate: true,
      deep: true
    }
  },
  methods: {
    reset() {
      this.fileList = []
      this.filePlanList = []
    },

    handleBeforeUpload(file) {
      const { name } = file
      let nameTemp = name.split('.')[0]
      nameTemp = Number(nameTemp)
      if (!Number.isInteger(nameTemp)) {
        // 重命名只能是阿拉伯数字
        this.$modal.msgError('视频重命名错误，请检查')
        return false
      }

      const isMp4 = file.type === 'video/mp4'
      // 限制文件最大不能超过 2000MB
      const isLt2M = file.size / 1024 / 1024 < 2000

      if (!isMp4) {
        this.$modal.msgError('视频只能是mp4格式!')
      }
      if (!isLt2M) {
        this.$modal.msgError('上传视频大小不能超过 2000MB!')
      }
      return isMp4 && isLt2M
    },
    // 删除视频
    handleDelete() {
      this.uploadVideo = {}
      this.$emit('update:ossId', '')
    },

    // 上传成功回调
    handleUploadSuccess(result) {
      this.$emit('successResult', result)
    },

    // 获取oss的sts令牌
    async queryGetStsTokenFn() {
      const res = await queryGetStsToken()
      const {
        AccessKeyId,
        AccessKeySecret,
        Expiration,
        SecurityToken
      } = res

      const client = new OSS({
        // yourRegion填写Bucket所在地域。以华东1（杭州）为例，yourRegion填写为oss-cn-hangzhou。
        region: 'oss-cn-shenzhen',
        // 从STS服务获取的临时访问密钥（AccessKey ID和AccessKey Secret）。
        accessKeyId: AccessKeyId,
        accessKeySecret: AccessKeySecret,
        // 从STS服务获取的安全令牌（SecurityToken）。
        stsToken: SecurityToken,
        // 填写Bucket名称，例如examplebucket。
        bucket: 'playlet-video-asset'
      })
      this.client = client
    },

    // 上传
    async uploadHttp(event) {
      const file = event.file
      this.fileList.push(file)

      const sizeMB = Math.trunc(file.size / 1024 / 1024)
      this.filePlanList.push({
        fileName: file.name,
        fileSize: sizeMB
      })
      this.$emit('uploadLoading')

      if (this.timer) clearTimeout(this.timer)
      this.timer = setTimeout(() => {
        this.asyncPoolFn()
      }, 0)
    },

    async asyncPoolFn() {
      const timeout = i => new Promise(resolve => setTimeout(async() => {
        // 每次都重新获取oss临时令牌
        await this.queryGetStsTokenFn()

        const file = this.fileList[i]
        this.uploadHttpOss(file, i).then(data => {
          const {
            id,
            old_file_name
          } = data
          // 集数，取视频重命名的名称，重命名名称应该设置为10.mp4、11.mp4、15.mp4
          const episodes_temp = old_file_name.split('.')[0]
          // 剧集集数-ossid，英文逗号隔开
          const ids_item = `${episodes_temp}-${id}`

          // 添加剧集到数据库
          addBatchEpisode({
            library_id: this.$props.library_id,
            episode_ids: ids_item
          }).then(res => {
            this.$modal.msgSuccess(`${old_file_name}添加成功`)
            this.$emit('onceSuccess')
            resolve(ids_item)
          })
        })
      }, i))

      // 用视频数组下标来做并发控制
      const indexArr = this.fileList.map((e, index) => index)
      const result = await this.asyncPool(1, indexArr, timeout)
      console.log('asyncPoll执行结果', result)
      this.handleUploadSuccess(result)
    },

    /** 上传视频到OSS上，OSS直传 */
    uploadHttpOss(file, fIndex) {
      return new Promise((resolve) => {
        console.log('uploadHttpOss()==file==', file)
        const fileName = '/tmp/' + file.name
        let duration = 0
        const video_folder = this.$props.video_folder
        // 传入file
        const binaryData = [file]
        // 获取视频或者音频时长
        const fileUrl = URL.createObjectURL(new Blob(binaryData, { type: 'application/zip' }))
        let durationPromise = {}
        try {
          // 经测试，发现audio也可获取视频的时长
          console.log('audioElement==before')
          const audioElement = new Audio(fileUrl)
          console.log('audioElement==', audioElement)
          durationPromise = new Promise(resolve => {
            audioElement.addEventListener('loadedmetadata', function(_event) {
              duration = audioElement.duration
              audioElement.pause()// 直到播放结束或是被暂停（例如调用 pause()）。在那个时候，这个对象才会成为垃圾回收的目标。
              audioElement.remove()
              console.log('视频的时长为:', duration)// 单位：秒
              resolve(duration)
            })
          })
        } catch (e) {
          console.error('获取视频时长错误')
          console.error(e)
        }
        // durationPromise.then(timeLength => {
        //   const options = {
        //     callback: {
        //     // 设置回调请求的服务器地址，且要求必须为公网地址。
        //       url: process.env.VUE_APP_BASE_API + '/common/oss/ossCallBack',
        //       // 设置回调请求消息头中Host的值，即您的服务器配置的Host值。
        //       // host: 'yourHost',
        //       // 设置发起回调时请求body的值。
        //       body: 'bucket=${bucket}&object=${object}&etag=${etag}&size=${size}&mimeType=${mimeType}&imageInfo_height=0&imageInfo_width=0&imageInfo.format=${imageInfo.format}&type=${x:type}&video_duration=${x:video_duration}&library_dir=${x:library_dir}',
        //       // 设置发起回调请求的Content-Type。
        //       contentType: 'application/x-www-form-urlencoded',
        //       // 设置发起回调请求的自定义参数。
        //       customValue: {
        //         type: 'video_main', // 短剧库的每一集
        //         video_duration: Math.ceil(timeLength).toString(),
        //         library_dir: video_folder
        //       }
        //     }
        //   }
        //   // object-name可以自定义为文件名（例如file.txt）或目录（例如abc/test/file.txt）的形式，实现将文件上传至当前Bucket或Bucket下的指定目录。
        //   this.client.put(fileName, file, options).then(res => {
        //     console.log('阿里云直传成功，后端逻辑处理成功=', res)
        //     const data = res.data.data
        //     resolve(data)
        //   // 一下为生成图片处理的签名 URL t_1000表示第一秒视频图片，常用来作为视频封面图
        //   // const imgRes = this.video_url + '?x-oss-process=video/snapshot,t_1000,f_jpg,w_0,h_0,m_fast'
        //   }).catch(() => {
        //     this.fileList = []
        //   })
        // })
        durationPromise.then(timeLength => {
          const options = {
            // 获取分片上传进度、断点和返回值。
            progress: (p, cpt, res) => {
              // console.log(p)
              const temp = p * 100
              this.filePlanList[fIndex].progress = Math.trunc(temp)
              this.$forceUpdate()
            },
            // 设置并发上传的分片数量。
            parallel: 4,
            // 设置分片大小。默认值为1 MB，最小值为100 KB。
            partSize: 1 * 1024 * 1024, // 1MB
            // headers,
            // 自定义元数据，通过HeadObject接口可以获取Object的元数据。
            // meta: { year: 2020, people: 'test' },
            mime: 'video/mp4',
            callback: {
            // 设置回调请求的服务器地址，且要求必须为公网地址。
              url: process.env.VUE_APP_BASE_API + '/common/oss/ossCallBack',
              // 设置回调请求消息头中Host的值，即您的服务器配置的Host值。
              // host: 'yourHost',
              // 设置发起回调时请求body的值。
              body: 'bucket=${bucket}&object=${object}&etag=${etag}&size=${size}&mimeType=${mimeType}&imageInfo_height=0&imageInfo_width=0&imageInfo.format=${imageInfo.format}&type=${x:type}&video_duration=${x:video_duration}&library_dir=${x:library_dir}',
              // 设置发起回调请求的Content-Type。
              contentType: 'application/x-www-form-urlencoded',
              // 设置发起回调请求的自定义参数。
              customValue: {
                type: 'video_main', // 短剧库的每一集
                video_duration: Math.ceil(timeLength).toString(),
                library_dir: video_folder
              }
            }
          }
          this.client.multipartUpload(fileName, file, options).then(res => {
            console.log('阿里云直传成功，后端逻辑处理成功=', res)
            const data = res.data.data
            resolve(data)
            // 一下为生成图片处理的签名 URL t_1000表示第一秒视频图片，常用来作为视频封面图
            // const imgRes = this.video_url + '?x-oss-process=video/snapshot,t_1000,f_jpg,w_0,h_0,m_fast'
          }).catch((err) => {
            console.error(err)
            this.aliError = true
            this.fileList = []
          })
        })
      })
    },

    /**
     * poolLimit(数字类型)：表示限制的并发数;
     * array(数组类型)：表示任务数组;
     * iteratorFn(函数类型)：表示迭代函数，用于实现对每个任务项进行处理，该函数会返回一个 Promise 对象或异步函数。
     * */
    asyncPool(poolLimit, array, iteratorFn) {
      let i = 0
      const ret = []
      // 存储所有的异步任务
      const executing = []
      // 存储正在执行的异步任务
      const enqueue = function() {
        if (i === array.length) {
          return Promise.resolve()
        }
        const item = array[i++]
        // 获取新的任务项
        const p = Promise.resolve().then(() => iteratorFn(item, array))
        ret.push(p)
        let r = Promise.resolve()
        // 当poolLimit值小于或等于总任务个数时，进行并发控制
        if (poolLimit <= array.length) {
        // 当任务完成后，从正在执行的任务数组中移除已完成的任务
          const e = p.then(() => executing.splice(executing.indexOf(e), 1))
          executing.push(e)
          if (executing.length >= poolLimit) {
            r = Promise.race(executing)
          }
        }
        // 正在执行任务列表 中较快的任务执行完成之后，才会从array数组中获取新的待办任务
        return r.then(() => enqueue())
      }
      return enqueue().then(() => Promise.all(ret))
    }

  }
}
</script>

<style lang="scss" scoped>
.editPage__video {
  .avatar-uploader .el-upload {
    border: 1px dashed #d9d9d9;
    border-radius: 6px;
    cursor: pointer;
    position: relative;
    overflow: hidden;
  }
  .avatar-uploader .el-upload:hover {
    border-color: #409eff;
  }
  .avatar-uploader-icon {
    font-size: 16px;
    color: #8c939d;
    width: 350px;
    height: 30px;
    line-height: 30px;
    text-align: center;
  }
  .avatar {
    width: 350px;
    height: auto;
    display: block;
  }
  .title {
    font-size: 18px;
    margin-bottom: 20px;
  }
  .img__con {

    .el-button {
      width: 100%;
      margin: 10px 0 20px 0;
    }
  }

  .plan-nav {
    margin-top: 22px;
    max-height: 360px;
    overflow-y: scroll;
    display: flex;
    justify-content: space-between;
    flex-wrap: wrap;
    .plan-item {
      display: flex;
      align-items: center;
      width: 100%;
    }
    ::v-deep .el-progress {
      flex: 1;
    }
    ::v-deep .el-progress-bar {
      flex: 1;
    }
    .file-name-p {
      color: #333333;
      font-size: 14px;
      margin-right: 20px;
    }
  }
  .plan-nav:after {
    content: '';
    width: 33%;
  }
  .plan-nav::-webkit-scrollbar {
    width: 4px;
  }
  .plan-nav::-webkit-scrollbar-thumb {
    border-radius: 10px;
    background: rgba(0,0,0,0.2);
  }
  .plan-nav::-webkit-scrollbar-track {
    border-radius: 0;
    background: rgba(0,0,0,0.1);
  }
}
</style>
